Skip to content

Conversation

@jackwotherspoon
Copy link
Collaborator

@jackwotherspoon jackwotherspoon commented Jun 4, 2024

Today, the Python Connector for async usage does not allow being called across
multiple event loops.

However, we do not explicitly define that logic nor make it clear via an error message.

This PR adds an error message to check in connect_async if the Connector._loop
attribute matches the current running event loop and errors if it does not (multiple event loops).

Related to #1107

@jackwotherspoon jackwotherspoon self-assigned this Jun 4, 2024
@jackwotherspoon jackwotherspoon marked this pull request as ready for review October 1, 2024 17:24
@jackwotherspoon jackwotherspoon requested a review from a team as a code owner October 1, 2024 17:24
Copy link
Collaborator

@kgala2 kgala2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

@hessjcg hessjcg merged commit 3030b82 into main Sep 29, 2025
17 checks passed
@hessjcg hessjcg deleted the error-on-loop branch September 29, 2025 22:12
@palash-taneja
Copy link

i think this check is too restrictive and breaks my FastAPI application that uses SQLAlchemy and asyncpg. maybe it's better to track the loop ids instead of comparing the objects.

here's a stack trace:
https://gist.github.com/palash-taneja/5e5cf3947d95bfe886479caf8bcd8d27

@hessjcg
Copy link
Collaborator

hessjcg commented Nov 4, 2025

@palash-taneja,

I did some research, and I have an alternate explanation: Your application likely has more than one event loop.

The code in the connector here correctly compares event loops. There is no possibility that the same asyncio event loop can be represented by two distinct loop objects.

Here's the evidence from your stack trace that your app has more than one event loop:

The first loop is runs the FastAPI router and the Cloud SQL Connector. This is the current loop when your application logs this message: "cloud_sql.py:116] [CLOUD_SQL] connect_async called from loop 5503254560, Connector was created in loop 550325456".

Then, the code calls the SQLAlchemy code session.execute(). SQLAlchemy session calls await greenlet_spawn at sqlalchemy/ext/asyncio/session.py:449. This likely switches the execution from the FastAPI event loop to a different one, probably the loop that was active when the SQLAlchemy library was initialized. I would look into how the SQLAlchemy library is initialized and make sure that its event loop matches the one in the connector. I hope you figure this out.

@palash-taneja
Copy link

palash-taneja commented Nov 4, 2025

@hessjcg where are you seeing that in the log I sent? I think there's a mistake/some clipping of the text because the log says

"cloud_sql.py:116] [CLOUD_SQL] connect_async called from loop 5503254560, Connector was created in loop 5503254560"

not "cloud_sql.py:116] [CLOUD_SQL] connect_async called from loop 5503254560, Connector was created in loop 550325456".

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants